#ifndef AVALON_UIDCLIENT_HPP
#define AVALON_UIDCLIENT_HPP
#include "Avalon/IO/ClientConnection.hpp"
#include "Avalon/IO/ConnectionState.hpp"
#include "Avalon/Serialization/Serialization.hpp"
#include "Avalon/ServiceLocator/ServiceLocatorServices.hpp"
#include "Avalon/Services/ServiceNode.hpp"
#include "Avalon/SignalHandling/TaskSignalHandler.hpp"

namespace Avalon {
namespace UidService {

  /*! \class UidClient
   *  \brief Client side of the UID service.
   *  \author Kamal Mansouri <kranar@hotmail.com>
   */
  class UidClient : public IO::ClientConnection {
    public:

      //! Creates a UidClient.
      /*!
        \param serviceClient The ServiceLocatorClient to use for this session.
        \param channel An unused Channel to the UidServer.
        \param dataShuttleFactory Specifies the type of serialization to use.
        \param heartbeatTimer The Timer used for heartbeats.
        \param timeout The Connection timeout.
        \param threadPool The ThreadPool used for requests.
      */
      UidClient(ServiceLocator::ServiceLocatorClient* serviceClient,
        IO::Channel* channel,
        Serialization::DataShuttleFactory* dataShuttleFactory,
        Threading::Timer* heartbeatTimer,
        boost::posix_time::time_duration timeout,
        Threading::ThreadPool& threadPool);

      virtual ~UidClient();

      //! Returns the next available UID.
      long long GetNextUid();

      virtual bool IsConnected() const;

      virtual void Connect();

      virtual void Close();

      virtual boost::signals2::connection ConnectClosedSignal(
        const ClosedSignal::slot_type& slot) const;

      virtual boost::signals2::connection ConnectClosedSignal(
        const ClosedSignal::slot_type& slot, Out<bool> isConnected) const;

    private:
      mutable boost::mutex m_mutex;
      ServiceLocator::ServiceLocatorClient* m_serviceClient;
      IO::ConnectionState m_serviceClientState;
      boost::scoped_ptr<IO::Channel> m_channel;
      IO::ConnectionState m_channelState;
      bool m_isConnected;
      bool m_isAuthenticating;
      bool m_isAuthenticated;
      boost::condition_variable m_authenticationCondition;
      Services::ServiceNode m_service;
      boost::condition_variable m_closedCondition;
      mutable ClosedSignal m_closedSignal;
      long long m_nextUid;
      long long m_lastUid;
      long long m_blockSize;
      SignalHandling::TaskSignalHandler m_signalHandler;

      void Shutdown();
      void OnServiceClientClosed();
      void OnConnectionClosed();
      void OnGetSessionIdRequest(const Services::RequestToken<
        ServiceLocator::GetSessionIdService>& request, unsigned int key);
      void OnSessionAuthentication(IO::Channel* channel, bool passed);
  };
}
}

#endif // AVALON_UIDCLIENT_HPP
